// i.r(t), i.d(t, { default: () => CameraStartModule })

import SnapshotsData from "../data/SnapshotsData"
import CameraStartData, { CameraStartPose } from "../data/CameraStartData"
import Module from "./Module"
import NavigationUrl from "../utils/NavigationUrl"
import Message from "../message/message"

class StartLocationSetMessage extends Message {
  is360: any
  constructor(e) {
    super(), (this.is360 = e)
  }
}
import Logger from "../utils/Logger"
import SweepData from "../data/SweepData"
import d from "../math/19674"

import { SaveCommand } from "../command/data.command"

import { SetCameraStartCommand } from "../command/camera.command"
import { ObjectSync } from "../storage/DataSync"
import Store from "../storage/Store"
import { dateISO, getDate } from "../utils/date.util"
import ExpiringResource from "../utils/ExpiringResource"

const deserialize = e => {
    if (!e) return null
    const t = new CameraStartData()
    if (!e.icon) return null
    t.modified = getDate(e && e.modified)
    t.icon = e.icon || void 0
    const i = 250
    const n = Math.ceil(140.625)
    const r = e.image ? `${e.image}&width=${i}&height=${n}&fit=crop&imgopt=1` : void 0
    t.thumb = r ? new ExpiringResource(r, null) : void 0
    return t
  },
  M = (e, t) => {
    const i = t && "icon" in t ? t : e
    return { modified: dateISO(i.modified), icon: i.icon }
  }

import DataSyncStore from "../storage/DataSyncStore"

export class MarketMonitor<T extends typeof Data = typeof Data> {
  hasChanges: boolean
  changedHandlers: ((...e: any) => T["prototype"])[]
  target: T["prototype"]
  constructor(e: MarketContext, t: T) {
    this.hasChanges = !1
    this.changedHandlers = []
    e.waitForData<T>(t).then(e => {
      this.target = e
      e.onChanged(() => {
        this.hasChanges = !0
        this.triggerChangeHandlers(this.target)
      })
    })
  }
  hasDiffRecord() {
    return this.hasChanges
  }
  getDiffRecord() {
    return this.target
  }
  clearDiffRecord() {
    this.hasChanges = !1
  }
  commitChanges() {
    this.triggerChangeHandlers(this.getDiffRecord())
  }
  onChanged(e: any) {
    this.changedHandlers.push(e)
  }
  removeOnChanged(e: any) {
    removeArrayItem(this.changedHandlers, e)
  }
  triggerChangeHandlers(e: any) {
    if (this.changedHandlers.length > 0) for (const t of this.changedHandlers) t(e)
  }
}
import ModelData from "../data/ModelData"
import { removeArrayItem } from "../utils/array.util"
import dataTypeEnum from "../enum/dataType.enum"
import { isPanOrMesh } from "../utils/viewmode.util"
import viewmodeEnum from "../enum/viewmode.enum"
import EngineContext from "../EngineContext"
import MarketContext from "../MarketContext"
import Data from "../object/Data"

const P = new Logger("camera-start")
export default class CameraStartModule extends Module {
  store: DataSyncStore
  engine: EngineContext
  sweepData: SweepData
  modelData: ModelData
  snapshotsData: SnapshotsData
  startingPose: CameraStartPose
  data: CameraStartData
  constructor() {
    super(...arguments), (this.name = "camera-start"), (this.store = null)
  }
  async init(e, t) {
    var i
    this.engine = t
    ;[this.sweepData, this.modelData, this.snapshotsData] = await Promise.all([
      t.market.waitForData(SweepData),
      t.market.waitForData(ModelData),
      t.market.waitForData(SnapshotsData)
    ])
    this.store = this.getStore(e)
    let r = this.modelData.model.image
    if (!e.readonly && this.store instanceof DataSyncStore) {
      const e = await this.store.read()
      e && e.icon && (r = e.icon)
    }

    const a = NavigationUrl.deserialize()
    if (a) {
      const e = this.parseNavigationPose(a)
      if (this.validStartPano(e)) {
        this.startingPose = new CameraStartPose()
        this.startingPose.copy(e)
        P.debug("Starting Camera Pose", this.startingPose)
      } else {
        P.error("Invalid start pose", e)
      }
    }
    this.bindings.push(this.engine.commandBinder.addBinding(SetCameraStartCommand, async e => this.updateStartLocationFromSnapshot(e.snapshotSid)))
    const l = r
    const c = this.getIconThumbnail(l)
    const d = this.getIconStartPose(l) || this.getStartFallback()
    if (null === (i = null == d ? void 0 : d.pano) || void 0 === i ? void 0 : i.uuid) {
      const e = this.sweepData.getSweep(d.pano.uuid)
      e && !e.enabled && (P.warn(`Enabled hidden start sweep ${d.pano.uuid}`), (e.enabled = !0), e.commit())
    }
    this.data = new CameraStartData(l, c, d)
    t.market.register(this, CameraStartData, this.data)
  }
  getStore(e) {
    const { modelId, baseUrl, readonly, storageProvider, queue } = e
    P.info(`Loading camera start from ${storageProvider}`)

    const path = `${baseUrl}/scene-portal/api/v1/player/models/${modelId}`
    const publishStores = new Store.ReadOnlyStore({ queue, path, deserialize, cachedData: { data: null } })
    const sync = new ObjectSync({ publishStores: [publishStores] })
    if (!readonly) {
      const e = new MarketMonitor(this.engine.market, CameraStartData)
      sync.addMonitor(e)
    }
    return new DataSyncStore(sync, {
      dataType: dataTypeEnum.START_LOCATION,
      readonly,
      engine: this.engine
    })
  }
  getStartingPose() {
    return this.startingPose || this.data.pose
  }
  parseNavigationPose(e) {
    const { mode: t, quaternion: i, position: n, floorVisibility: s, sweepIndex: r, zoom: o } = e
    let { panoId: a } = e
    if (a && !this.sweepData.containsSweep(a)) {
      const e = this.sweepData.getSweepByUuid(a)
      e && (a = e.id)
    }
    if (!a && void 0 !== r) {
      const e = this.sweepData.getSweepByIndex(r)
      e ? (a = e.id) : P.debug(`Failed to load sweep index ${r}`)
    }
    return {
      mode: t,
      camera: { position: n, rotation: i, zoom: o },
      pano: { uuid: a },
      floorVisibility: s
    }
  }
  async updateStartLocationFromSnapshot(e) {
    const t = this.snapshotsData.get(e),
      i = this.buildCameraStart(t),
      n = new CameraStartData(t.sid, t.thumbnailUrl, i)
    this.data.copy(n),
      this.data.commit(),
      this.engine.broadcast(new StartLocationSetMessage(t.is360)),
      await this.engine.commandBinder.issueCommand(new SaveCommand({ dataTypes: [dataTypeEnum.START_LOCATION] }))
  }
  buildCameraStart(e) {
    const t: any = {
      mode: e.metadata.cameraMode,
      camera: {
        position: e.metadata.cameraPosition,
        rotation: e.metadata.cameraQuaternion,
        zoom: e.metadata.orthoZoom
      },
      pano: {}
    }
    return isPanOrMesh(t.mode) && (t.pano = { uuid: e.metadata.scanId }), (t.floorVisibility = e.metadata.floorVisibility), t
  }
  defaultCameraStart(e) {
    return {
      mode: viewmodeEnum.Panorama,
      camera: {
        position: e.position,
        rotation: d.Z(e.rotation),
        zoom: 0
      },
      pano: { uuid: e.id }
    }
  }
  validStartPano(e) {
    return !!e && (!isPanOrMesh(e.mode) || (!!e.pano.uuid && this.sweepData.containsSweep(e.pano.uuid)))
  }
  getStartFallback() {
    const e = this.sweepData.getFirstAlignedSweep() || this.sweepData.getFirstSweep()
    if (void 0 !== e) return this.defaultCameraStart(e)
  }
  getIconStartPose(e) {
    let t = null
    return (
      e && e in this.snapshotsData.collection && (t = new CameraStartPose().copy(this.buildCameraStart(this.snapshotsData.get(e)))),
      this.validStartPano(t) || (t = null),
      t
    )
  }
  getIconThumbnail(e) {
    if (e && e in this.snapshotsData.collection) return this.snapshotsData.get(e).thumbnailUrl
  }
}
